/* $Header: sig_analog.c,v 2.2 01/10/02 10:33:03 przybyls Exp $ */

/***********************************************************************/
/*                                                                     */
/*                  Copyright Hewlett-Packard Co. 1991, 1992           */
/*                                                                     */
/***********************************************************************/

/***********************************************************************/
/* MODULE NAME:  sig_analog.c                                          */
/* ============                                                        */
/*                                                                     */
/* Author:  Lesley Freed                                               */
/*                                                                     */
/* MODULE PURPOSE:  To process the DAC output and Attenuator output    */
/*                  signals after select, zero and ranging.            */
/*                                                                     */
/*                                                                     */
/*                                                                     */
/***********************************************************************/


/*****************************/
/*   GLOBAL INCLUDE FILES    */
/*****************************/

#include <typedefs.h>
#include <p_wkfile.h>
#include <wkfile.h>
#include <ramps.h>
#include <zone_config.h>
#include <zone_status.h>
#include <status.h>
#include <error.h>
#include <sig_types.h>
#include <sigpath.h>

/*****************************/
/*   GLOBAL VARIABLES        */
/*****************************/


/*****************************/
/*   EXTERNAL VARIABLES      */
/*****************************/


/*****************************/
/*   LOCAL DEFINES           */
/*****************************/



/*****************************/
/*   IMPLEMENT SECTION       */
/*****************************/

#ifndef mccabe
#pragma SECTION PROG=SysCode
#endif

/* Constant Lookup Table for Ranging */

const	U_INT32	RANGE_REM_TABLE[] =
{
   0x00000000,	/* Mask for Range 5,  Attn 0  */  
   0x00000001,	/* Mask for Range 6,  Attn 1  */  
   0x00000003,	/* Mask for Range 7,  Attn 2  */  
   0x00000007,	/* Mask for Range 8,  Attn 3  */  
   0x0000000f,	/* Mask for Range 9,  Attn 4  */  
   0x0000001f,	/* Mask for Range 10, Attn 5  */  
   0x0000003f,	/* Mask for Range 11, Attn 6  */  
   0x0000007f,	/* Mask for Range 12, Attn 7  */  
   0x000000ff,	/* Mask for Range 13, Attn 8  */  
   0x000001ff,	/* Mask for Range 14, Attn 9  */  
   0x000003ff,	/* Mask for Range 15, Attn 10 */  
};	



/***********************************************************************/
/* FUNCTION:  DACSignalPath                                            */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:  To process the DAC output signal after select, zero and   */
/*           ranging.  Note that the pointer pSignal is assigned to    */
/*           point to the appropriate signal by ServiceSigpath.        */
/*                                                                     */
/* RETURNED VALUE:  none                                               */
/*                                                                     */
/* GLOBALS USED:  pSignal: ptr to signal status and working setpoints  */
/*                                                                     */
/* CALLED BY: SigPath                                                  */
/*                                                                     */
/* LIMITATIONS:  Assumes that the data from the calling routine,       */
/*               s_signal, has been clamped to a 24-bit unsigned value.*/
/*                                                                     */
/*                                                                     */
/***********************************************************************/

void DACSignalPath(INT32 s_signal)
{
	U_INT8 s_temp;

	/* Add the DAC Offset.  NOTE:  The input data, s_signal has already   */
	/* been clamped to 24-bit max positive, so we won't have 32-bit over- */
	/* flow.                                                              */

	s_signal += DAC_OFFSET;

	/* Clamp to 24-bit unsigned data */
	if ( s_signal > MAX_24BIT_VALUE ) 
	{
		s_signal = MAX_24BIT_VALUE;
	}
	else 
	/* Clamp negative data to zero   */
	{
		if (s_signal < 0) 
		{
			s_signal = 0x0;		
		}
	}

	if (pSignal->active_wkfile->DAC_rate == DAC_RATE_3HZ)
	/* 3 Hz Data */
	{
	/* Apply a n-point boxcar filter.  We will subtract the oldest data   */
	/* point and add the most recent.                                     */

		/* Get index into the array for the oldest data point         */
		s_temp = pSignal->ptr_filter_3_DAC;		

		/* Subtract the oldest data point from the running sum        */
		pSignal->filter_sum_3_DAC -= pSignal->filter_3_DAC[s_temp];

		/* Add the new data point to the running sum                  */
		pSignal->filter_sum_3_DAC += s_signal;
	
		/* Store the new data point in the array                      */
		pSignal->filter_3_DAC[s_temp] = s_signal;
		
		/* Update the filter array pointer to point to the new oldest */
		/*  data point.  If the pointer is to the top of the array    */
		/*  put it down to the bottom of the array which is actually  */
		/*  a circular buffer, otherwise move it up one position.     */

		if (s_temp)
		{
			pSignal->ptr_filter_3_DAC = --s_temp;		
		}
		else
		{
			pSignal->ptr_filter_3_DAC = DAC_ARRAY_SIZE_3HZ-1;
		}

		/* Scale the result by 16/256.  To keep resolution we will    */
		/* first multiply the result by 16, then add the remainder    */
		/* from the previous divide and then divide by 256, storing   */
		/* the new remainder for next time.                           */

		/* Compute (s_signal*16+remainder]/256)                       */
		pSignal->filter_out_DAC = Scale3Hz(pSignal->filter_sum_3_DAC, 
			                  pSignal->filter_out_DAC.remainder);
	}
	else 
	/* 30 Hz Data */
	{
		/* Put the latest data point into the filter output. */
		/* Scale the result by 2 to match the filtered data  */
		/* scaling.                                          */
		pSignal->filter_out_DAC.quotient  = s_signal << 1;
		pSignal->filter_out_DAC.remainder = 0;
	}

	pSignal->DAC_out = pSignal->filter_out_DAC.quotient;

	/* Clamp output to 10V max.  This is 24-bit unsigned maximum. */
	if ( pSignal->DAC_out > MAX_24BIT_VALUE )
	{
		pSignal->DAC_out = MAX_24BIT_VALUE;
	}
}


/***********************************************************************/
/* FUNCTION: ATTNSignalPath                                            */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:  To compute the 8-bit attenuator output from the raw       */
/*           analog signal after the zero offset compensation and      */
/*           ranging have been applied.  Note that the pointers        */
/*           pSignal is assigned to point to the appropriate signal    */
/*           by the function ServiceSigpath.                           */
/*                                                                     */
/* CALLED BY: SigPath                                                  */
/*                                                                     */
/* RETURNED VALUE: none.                                               */
/*                                                                     */
/* LIMITATIONS:  Assumes that the data from the calling routine,       */
/*               s_signal, has been clamped to a 24-bit unsigned value.*/
/*                                                                     */
/***********************************************************************/

void ATTNSignalPath(INT32 s_signal)
{
	U_INT8 s_temp;

	/* Add the ATTN Offset.  NOTE:  The input data, s_signal has already  */
	/* been clamped to 24-bit max positive, so we won't have 32-bit over- */
	/* flow.                                                              */

	s_signal += ATTN_OFFSET_SCALED;

	/* Clamp to 26-bit unsigned data.  NOTE:  This is because the largest */
	/* meaningful number for the attn is 16-bit and we allow a maximum of */
	/* 10 as our attn factor.                                             */
	if ( s_signal > MAX_26BIT_VALUE ) 
	{
		s_signal = MAX_26BIT_VALUE;
	}
	else 
	/* Clamp negative data.  NOTE:  We will not clamp it to zero yet since*/
	/* we will be applying the offset again for signals with non-zero attn*/
	{
		if (s_signal < -0x800 ) 
		{
			s_signal = -0x800;		
		}
	}

	/* Apply the 3 Hz Filter.  This is a 16-point boxcar filter.  We will */
	/* subtract the oldest data point and add the most recent.            */

	/* Get index into the array for the oldest data point         */
	s_temp = pSignal->ptr_filter_3_ATTN;		

	/* Subtract the oldest data point from the running sum        */
	pSignal->filter_sum_3_ATTN -= pSignal->filter_3_ATTN[s_temp];

	/* Add the new data point to the running sum                  */
	pSignal->filter_sum_3_ATTN += s_signal;
	
	/* Store the new data point in the array                      */
	pSignal->filter_3_ATTN[s_temp] = s_signal;
		
	/* Update the filter array pointer to point to the new oldest */
	/*  data point.  If the pointer is to the top of the array    */
	/*  put it down to the bottom of the array which is actually  */
	/*  a circular buffer, otherwise move it up one position.     */

	if (s_temp)
	{
		pSignal->ptr_filter_3_ATTN = --s_temp;		
	}
	else
	{
		pSignal->ptr_filter_3_ATTN = ARRAY_SIZE_3HZ-1;		
	}

	/* Scale the result by 32/64. To keep the resolution we will  */
        /* multiply the result by 32, then add the remainder from the */
        /* previous divide and then divide by 64, storing the new     */
        /* remainder for next time.                                   */

	/* Compute (s_signal*32+remainder)/64 * 1.11 to compensate for*/
	/* the equivalent hw gain of the DAC outputs.                 */
	pSignal->filter_out_ATTN = ScaleAttn3Hz(pSignal->filter_sum_3_ATTN, 
		                            pSignal->filter_out_ATTN.remainder);

	/* Check to see if ATTN output is enabled */
	if (pSignal->zero_attn_on_off & ATTN_ON_MASK) 
	/* ATTN ON */
	{
	/* Calculate 8-bit ATTN output and 8-bit remainder.  NOTE:  We are    */
        /* done using s_signal in its original form so now we will used the   */
        /* filtered version.                                                  */
		s_signal = pSignal->filter_out_ATTN.quotient;

	/* Apply ATTN range */
		/* Get the output by shifting the data right by ATTN setpt    */

		/* First, add in the remainder from the previous attenuation  */
		s_signal += pSignal->attn_rem;

		s_temp = pSignal->attn;	        /* s_temp = attenuation       */

		/* Get the remainder lost by masking off all but the bits     */
		/* lost by shifting.                                          */
		pSignal->attn_rem = s_signal & RANGE_REM_TABLE[s_temp];

		/* Apply the attenuation                                      */
		s_signal = s_signal >> s_temp;

		/* Add back the ATTN offset lost due to the attenuation.      */
		/* That is, we added the hardware offset before in order to   */
		/* have unsigned numbers for the filtering, but due to the    */
		/* attenuation scaling our offset has been reduced to:        */
		/* ATTN_OFFSET/2^N, where N is the attenuation.               */
		s_signal += ATTN_OFFSET - (ATTN_OFFSET >> s_temp);

		/* Add the remainder from previous output */
		s_signal += pSignal->ATTN_out.remainder;

		/* Clamp output to 16-bit maximum */
		if (s_signal > 0xffff) 
		{
			s_signal = 0xffff;
		}
                else
	        /* Clamp negative data to 0 */
	        {
			if (s_signal < 0) 
			{
				s_signal = 0;		
			}
		}

		/* Get the remainder which is the 8 LS-bits */	
		pSignal->ATTN_out.remainder = s_signal & 0x00ff;

		/* Get the output which is the 8 MS-bits */
		pSignal->ATTN_out.output = s_signal >> 8;

		/* Before outputing to the Attenuator check to see if we      */
		/* should be outputting a START RUN TICK MARK.  This tick     */
		/* mark lasts for approximately .2 seconds or 20/100 Hz       */
		/* where 20 is the number of counts to assert the tick mark.  */

		if ( Attn_Start_Tick_Count )
		{

                   /* Check for possible underflow.  The attenuator output    */
                   /* maps zero to zero volts and 0ffh to 1mV                 */
		   if ( pSignal->ATTN_out.output <= ATTN_TICK_SIZE )
		   {
                      /* Clamp at zero */
		      pSignal->ATTN_out.output = 0;
		   }
		   else
		   {
                      /* Subtract tick from data */
		      pSignal->ATTN_out.output -= ATTN_TICK_SIZE;
		   }

                   /* Decrement tick count */
		   --Attn_Start_Tick_Count;
		}
	}
	else	
	/* ATTN OFF */
	{
	/* Set output to ATTN Offset */
		/* output is offset   */
		pSignal->ATTN_out.output = ATTN_OFFSET_OUTPUT; 
		/* set remainder to 0 */
		pSignal->ATTN_out.remainder = 0;	
	}
}	


